package cc.iotkit.openapi.controller;

import cc.iotkit.common.api.PageRequest;
import cc.iotkit.common.api.Paging;
import cc.iotkit.common.constant.Constants;
import cc.iotkit.common.thing.ThingModelMessage;
import cc.iotkit.data.manager.IDeviceInfoData;
import cc.iotkit.data.service.DeviceInfoDataImpl;
import cc.iotkit.manager.dto.vo.deviceinfo.DeviceDataVo;
import cc.iotkit.manager.dto.vo.deviceinfo.DeviceInfoVo;
import cc.iotkit.manager.dto.vo.record.DoorAccessStaticVo;
import cc.iotkit.manager.service.AlertService;
import cc.iotkit.manager.service.DoorAccessRecordService;
import cc.iotkit.model.alert.AlertRecord;
import cc.iotkit.model.device.DeviceInfo;
import cc.iotkit.model.device.message.DevicePropertyCache;
import cc.iotkit.model.report.DoorAccessRecord;
import cc.iotkit.temporal.IThingModelMessageData;
import cn.dev33.satoken.annotation.SaCheckLogin;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags = {"openapi-综合分析"})
@Slf4j
@RestController
@RequestMapping("/openapi/comprehensive")
public class ComprehensiveOpenApi {

    @Autowired
    @Qualifier("deviceInfoDataCache")
    private IDeviceInfoData deviceInfoData;

    @Autowired
    private DeviceInfoDataImpl deviceInfoDataImpl;

    @Autowired
    private DoorAccessRecordService doorAccessRecordService;
    @Autowired
    private AlertService alertService;
    @Autowired
    private IThingModelMessageData thingModelMessageData;

    @ApiOperation("1、设备运行情况")
    @GetMapping("/v1/runStatistics")
    @SaCheckLogin
    public JSONArray runStatistics() {

        long all = deviceInfoData.count();

        DeviceInfo condition = new DeviceInfo();
        DeviceInfo.State state = new DeviceInfo.State();
        state.setOnline(true);
        condition.setState(state);
        int online = deviceInfoData.findAllByCondition(condition).size();

        state.setOnline(false);
        condition.setState(state);
        int outline = deviceInfoData.findAllByCondition(condition).size();


        JSONArray jsonArray = new JSONArray();
        JSONObject object = new JSONObject();
        object.put("title","全部");
        object.put("value",all);
        object.put("type","all");
        jsonArray.add(object);

        object = new JSONObject();
        object.put("title","在线");
        object.put("value",online);
        object.put("type","online");
        jsonArray.add(object);

        object = new JSONObject();
        object.put("title","离线");
        object.put("value",outline);
        object.put("type","outline");
        jsonArray.add(object);

        object = new JSONObject();
        object.put("title","故障");
        object.put("value",0);
        object.put("type","bad");
        jsonArray.add(object);

        return jsonArray;
    }

    @ApiOperation("2、环境监控")
    @GetMapping("/v1/querySurroundingsData")
    @SaCheckLogin
    public JSONObject querySurroundingsData() {

        //温度
        float temp = 0f;
        float temp_mini= 0f;
        float temp_max=0f;
        //湿度
        float humidity = 0f;
        float humidity_mini = 0f;
        float humidity_max = 0f;
        //可燃气浓度
        float combustibleGas = 0f;
        float combustibleGas_mini = 0f;
        float combustibleGas_max = 0f;
        //可燃气体浓度
        float oxygen = 0f;
        float oxygen_min = 0f;
        float oxygen_max = 0f;



        //查询温湿度设备
        List<DeviceInfo> deviceInfoList = deviceInfoData.findByPk(Constants.HUMITURE_PK);
        if (deviceInfoList != null && deviceInfoList.size() > 0) {
            //循环查询设备 对应的属性【humidity 湿度，temperature 温度，gasStrength1 探头1暂定可燃气体，gasStrength2 探头2暂定氧气】
            for (DeviceInfo deviceInfo : deviceInfoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfo.getDeviceId());
                if (properties.get("temperature") != null) {
                    //累计温度
                    temp += Float.parseFloat(properties.get("temperature").getValue() + "");
                    if (temp_mini>Float.parseFloat(properties.get("temperature").getValue() + "")){
                        temp_mini = Float.parseFloat(properties.get("temperature").getValue() + "");
                    }

                    if (temp_max<Float.parseFloat(properties.get("temperature").getValue() + "")){
                        temp_max = Float.parseFloat(properties.get("temperature").getValue() + "");
                    }
                }
                if (properties.get("humidity") != null) {
                    //累计湿度
                    humidity += Float.parseFloat(properties.get("humidity").getValue() + "");
                    if (humidity_mini>Float.parseFloat(properties.get("humidity").getValue() + "")){
                        humidity_mini = Float.parseFloat(properties.get("humidity").getValue() + "");
                    }
                    if (humidity_max<Float.parseFloat(properties.get("humidity").getValue() + "")){
                        humidity_max = Float.parseFloat(properties.get("humidity").getValue() + "");
                    }
                }
            }
            temp = temp / deviceInfoList.size();
            humidity = humidity / deviceInfoList.size();
        }

        //氧气浓度
        deviceInfoList = deviceInfoData.findByPk(Constants.YQ_PK);
        if (deviceInfoList != null && deviceInfoList.size() > 0) {
            //循环查询设备 对应的属性【gasStrength 氧气浓度】
            for (DeviceInfo deviceInfo : deviceInfoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfo.getDeviceId());
                if (properties.get("gasStrength") != null) {
                    //累计温度
                    oxygen += Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    if (oxygen_max<Float.parseFloat(properties.get("gasStrength").getValue() + "")){
                        oxygen_max = Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    }
                    if (oxygen_min>Float.parseFloat(properties.get("gasStrength").getValue() + "")){
                        oxygen_min = Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    }
                }
            }
            oxygen = oxygen / deviceInfoList.size();
        }

        //可燃气体
        deviceInfoList = deviceInfoData.findByPk(Constants.KRQT_PK);
        if (deviceInfoList != null && deviceInfoList.size() > 0) {
            //循环查询设备 对应的属性【gasStrength 氧气浓度】
            for (DeviceInfo deviceInfo : deviceInfoList) {
                Map<String, DevicePropertyCache> properties = deviceInfoData.getProperties(deviceInfo.getDeviceId());
                if (properties.get("gasStrength") != null) {
                    //累计温度
                    combustibleGas += Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    if (combustibleGas_mini>Float.parseFloat(properties.get("gasStrength").getValue() + "")){
                        combustibleGas_mini = Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    }
                    if (combustibleGas_max<Float.parseFloat(properties.get("gasStrength").getValue() + "")){
                        combustibleGas_max = Float.parseFloat(properties.get("gasStrength").getValue() + "");
                    }
                }
            }
            combustibleGas = combustibleGas / deviceInfoList.size();
        }

        JSONObject object = new JSONObject();
        object.put("temperature",temp);
        object.put("temperature_mini",temp_mini);
        object.put("temperature_max",temp_max);


        object.put("humidity",humidity);
        object.put("humidity_mini",humidity);
        object.put("humidity_max",humidity);

        object.put("pressure",combustibleGas);
        object.put("pressure_max",combustibleGas_max);
        object.put("pressure_mini",combustibleGas_mini);

        object.put("oxygen",oxygen);
        object.put("oxygen_max",oxygen_max);
        object.put("oxygen_min",oxygen_min);

        return object;
    }

    @ApiOperation("3、安防监控")
    @GetMapping("/v1/securityData")
    @SaCheckLogin
    public JSONObject securityData() {
        //摄像头数量
        int cameraTotal = 0;
        List<DeviceInfo> deviceInfoList = deviceInfoData.findByPk(Constants.CAMERA_PK);
        if (deviceInfoList!=null){
            cameraTotal = deviceInfoList.size();
        }

        //门禁数量
        int accessControlTotal = 0;
        List<DeviceInfo> deviceInfos = deviceInfoData.findByPk(Constants.DOOR_PK);
        if (deviceInfos!=null){
            accessControlTotal = deviceInfos.size();
        }

        /**
         * 响应参数：
         *
         * | 字段名称           | 类型     | 说明         |
         * | ------------------ | -------- | ------------ |
         * | cameraTotal        | number   | 摄像头总数   |
         * | accessControlTotal | number   | 门禁总数     |
         * | charts             | ChartsVo | 图表数据     |
             * | xAxisData          | array    | X轴数据      |
             * | seriesData         | array    | 图表显示数据 |
         */

        List<DoorAccessStaticVo> doorAccessStaticVoList = doorAccessRecordService.staticCountByHours(null,new Date());

        JSONObject object = new JSONObject();
        object.put("cameraTotal",cameraTotal);
        object.put("accessControlTotal",accessControlTotal);
        int[] xAxisData = null;
        int[] seriesData = null;
        if (doorAccessStaticVoList!=null && doorAccessStaticVoList.size()>0) {
            xAxisData = new int[doorAccessStaticVoList.size()];
            seriesData = new int[doorAccessStaticVoList.size()];
        }
        for (int i=0;i<doorAccessStaticVoList.size();i++){
            xAxisData[i]=doorAccessStaticVoList.get(i).getHours();
            seriesData[i]= doorAccessStaticVoList.get(i).getCount();
        }
        JSONObject charts = new JSONObject();
        charts.put("xAxisData",xAxisData);
        charts.put("seriesData",seriesData);
        object.put("charts",charts);
        return object;
    }

    @ApiOperation("4、用电一览")
    @GetMapping("/v1/electricityDataDay")
    @SaCheckLogin
    public JSONObject electricityDataDay() {
        /**
         * 响应参数：
         *
         | 字段名称           | 类型     | 说明         |
         | ------------------ | -------- | ------------ |
         | currentConsumption | number   | 获取当前能耗（单位kw）   |
         | accumulateDay      | number   | 24小时累计用电（单位kw·h）|
         | charts             | ChartsVo | 图表数据     |
         | xAxisData          | array    | X轴数据      |
         | seriesData         | array    | 图表显示数据 |
         */

        List<DeviceInfo> deviceInfoList = deviceInfoData.findByPk(Constants.ELECTRICAL_MI_PK);
        Float accumulateDay = 0f;
        Float electricEnergy = 0f;
        List<String> ids = null;
        Date endDate = DateUtils.ceiling(new Date(), Calendar.HOUR);
        Date startDate = DateUtils.addDays(endDate, -1);
        for (DeviceInfo deviceInfo:deviceInfoList) {
            ids = new ArrayList<>();
            ids.add(deviceInfo.getDeviceId());

            List<ThingModelMessage> messageList = thingModelMessageData.findByTypeAndDeviceIdsAll(ids, ThingModelMessage.TYPE_PROPERTY, null, startDate.getTime(), endDate.getTime());
            messageList.sort(new Comparator<ThingModelMessage>() {
                @Override
                public int compare(ThingModelMessage o1, ThingModelMessage o2) {

                    int r = o1.getTime().compareTo(o2.getTime());
                    if (r == 0) {
                        return o1.getId().compareTo(o2.getId());
                    }
                    return r;

                }
            });
            float d1 = 0;
            float d2 = 0;
            float p1 = 0;
            float p2 = 0;
            if (messageList.size()>0) {
                Map<String, Object> o1 = (Map<String, Object>) messageList.get(0).getData();
                Map<String, Object> o2 = (Map<String, Object>) messageList.get(messageList.size() - 1).getData();
                if (o1 != null && o1.get("electricEnergy") != null) {
                    d1 = Float.parseFloat(o1.get("electricEnergy") + "");
                }
                if (o2 != null && o2.get("electricEnergy") != null) {
                    d2 = Float.parseFloat(o2.get("electricEnergy") + "");
                }
                if (o1 != null && o1.get("power") != null) {
                    p1 = Float.parseFloat(o1.get("power") + "");
                }
                if (o2 != null && o2.get("power") != null) {
                    p2 = Float.parseFloat(o2.get("power") + "");
                }
            }
            electricEnergy+=(d2-d1);
            accumulateDay+=(p2);
        }
        JSONArray seriesDataArr = new JSONArray();
        JSONObject object = new JSONObject();
        object.put("currentConsumption",accumulateDay);
        object.put("accumulateDay",electricEnergy);

        //填充近24小时数据
        int[] xAxisData24 = new int[24];
        int h=0;
        for (int i=startDate.getHours();i<24;i++){
            xAxisData24[h] = i;
            h++;
        }
        for (int i=1;i<endDate.getHours();i++){
            xAxisData24[h] = i;
            h++;
        }
        for (DeviceInfo deviceInfo:deviceInfoList) {
            List<String> devIds= new ArrayList<>();
            devIds.add(deviceInfo.getDeviceId());
            List<ThingModelMessage> thingModelMessageList = thingModelMessageData.findByTypeAndDeviceIdsAll(devIds,ThingModelMessage.TYPE_PROPERTY,null,startDate.getTime(),endDate.getTime());
            thingModelMessageList.sort(new Comparator<ThingModelMessage>() {
                @Override
                public int compare(ThingModelMessage o1, ThingModelMessage o2) {

                    int r = o1.getTime().compareTo(o2.getTime());
                    if (r == 0) {
                        return o1.getId().compareTo(o2.getId());
                    }
                    return r;

                }
            });
            // 将记录按小时聚合分组
            Map<LocalDateTime, List<ThingModelMessage>> groupedByHour = thingModelMessageList.stream()
                    .collect(Collectors.groupingBy(
                            x -> (new Date(x.getTime())).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().withMinute(0).withSecond(0).withNano(0) // 将时间设置为整点
                    ));

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("name",deviceInfo.getDeviceName());
            float[] floats = new float[24];
            for (Map.Entry<LocalDateTime, List<ThingModelMessage>> entry : groupedByHour.entrySet()) {
                LocalDateTime key = entry.getKey();
                List<ThingModelMessage> value = entry.getValue();

                for (int i=0;i<24;i++){
                    if (xAxisData24[i]==key.getHour()){
                            //聚合计算当前小时下的能耗
                            float a = 0f;
                            Map<String, Object> o1 = (Map<String, Object>) value.get(value.size()-1).getData();
                            Map<String, Object> o2 = (Map<String, Object>) value.get(0).getData();
                            if (o2 != null && o2.get("electricEnergy") != null && o1!=null && o1.get("electricEnergy") != null) {
                                a = Float.parseFloat(o2.get("electricEnergy")+"") - Float.parseFloat(o1.get("electricEnergy")+"");
                                if (a<0){
                                    a = Float.parseFloat(o1.get("electricEnergy")+"") - Float.parseFloat(o2.get("electricEnergy")+"");
                                }
                            }
                        floats[i] = a;
                        break;
                    }
                }
            }
            jsonObject.put("data",floats);
            seriesDataArr.add(jsonObject);
        }

        object.put("seriesData",seriesDataArr);
        object.put("xAxisData",xAxisData24);
        return object;
    }

    @ApiOperation("5、系统监控")
    @GetMapping("/v1/getSwitchCount")
    @SaCheckLogin
    public JSONArray getSwitchCount() {
        JSONArray jsonArray = new JSONArray();

        DeviceInfo condition = new DeviceInfo();
        DeviceInfo.State state = new DeviceInfo.State();
        condition.setState(null);
        condition.setProductKey(Constants.PFJ_PK);
        //排风机设备总数
        int pfjTotal = deviceInfoDataImpl.findAllByCondition(condition).size();
        //空调总数
        condition.setProductKey(Constants.AIR_PK);
        int airTotal = deviceInfoDataImpl.findAllByCondition(condition).size();
        //风阀总数
        condition.setProductKey(Constants.BFLF_PK);
        int airValveTotal = deviceInfoDataImpl.findAllByCondition(condition).size();
        condition.setProductKey(Constants.MFL_PK);
        airValveTotal += deviceInfoDataImpl.findAllByCondition(condition).size();
        condition.setProductKey(Constants.WXZ_PK);
        airValveTotal += deviceInfoDataImpl.findAllByCondition(condition).size();
        condition.setProductKey(Constants.TFG_PK);
        airValveTotal += deviceInfoDataImpl.findAllByCondition(condition).size();
        condition.setProductKey(Constants.SF_PK);
        airValveTotal += deviceInfoDataImpl.findAllByCondition(condition).size();
        condition.setProductKey(Constants.HF_PK);
        airValveTotal += deviceInfoDataImpl.findAllByCondition(condition).size();
        //自控【新风机组】
        condition.setProductKey(Constants.XFJZ_PK);
        int automaticTotal = deviceInfoDataImpl.findAllByCondition(condition).size();

        //在线设备统计
        state.setOnline(true);
        condition.setState(state);
        //排风机开
        condition.setProductKey(Constants.PFJ_PK);
        List<DeviceInfo> deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        int pfjTotal_online = 0;
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                pfjTotal_online+=1;
            }
        }
        if (pfjTotal_online==0){
            pfjTotal_online = deviceInfoList.size();
        }
        //空调开
        condition.setProductKey(Constants.AIR_PK);
        int airTotal_online = 0;
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);

        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airTotal_online+=1;
            }
        }
        //风阀开
        condition.setProductKey(Constants.BFLF_PK);
        int airValveTotal_online = 0;
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        condition.setProductKey(Constants.MFL_PK);
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        condition.setProductKey(Constants.WXZ_PK);
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        condition.setProductKey(Constants.TFG_PK);
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        condition.setProductKey(Constants.SF_PK);
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        condition.setProductKey(Constants.HF_PK);
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                airValveTotal_online+=1;
            }
        }

        //自控【新风机组】开
        condition.setProductKey(Constants.XFJZ_PK);
        int automaticTotal_online = 0;
        deviceInfoList = deviceInfoDataImpl.findAllByCondition(condition);
        for (DeviceInfo d:deviceInfoList) {
            Map<String, DevicePropertyCache> propertyCacheMap = deviceInfoData.getProperties(d.getDeviceId());
            if ("1".equals(propertyCacheMap.get("onOff").getValue())){
                automaticTotal_online+=1;
            }
        }

        state.setOnline(false);
        condition.setState(state);
        //排风机关
        int pfjTotal_offline = pfjTotal - pfjTotal_online;
        //空调关
        int airTotal_offline = airTotal-airTotal_online;

        //风阀关
        int airValveTotal_offline = airValveTotal - airValveTotal_online;

        //自控【新风机组】关
        int automaticTotal_offline = automaticTotal - automaticTotal_online;


        JSONObject object = new JSONObject();
        object.put("title","总");
        object.put("automaticTotal",automaticTotal);
        object.put("airTotal",airTotal);
        object.put("pfjTotal",pfjTotal);
        object.put("airValveTotal",airValveTotal);
        jsonArray.add(object);

        object = new JSONObject();
        object.put("title","开");
        object.put("automaticTotal",automaticTotal_online);
        object.put("airTotal",airTotal_online);
        object.put("pfjTotal",pfjTotal_online);
        object.put("airValveTotal",airValveTotal_online);
        jsonArray.add(object);

        object = new JSONObject();
        object.put("title","关");
        object.put("automaticTotal",automaticTotal_offline);
        object.put("airTotal",airTotal_offline);
        object.put("pfjTotal",pfjTotal_offline);
        object.put("airValveTotal",airValveTotal_offline);
        jsonArray.add(object);

        return jsonArray;
    }

    @ApiOperation("6、报警中心")
    @GetMapping("/v1/alarmData")
    @SaCheckLogin
    public JSONObject alarmData() {
        /**
         * 响应参数：
         *
         * | 字段名称         | 类型   | 说明         |
         * | ---------------- | ------ | ------------ |
         * | alarmTotal       | number | 报警记录数量 |
         * | maintenanceTotal | number | 保养记录数量 |
         */
        JSONObject object = new JSONObject();
        PageRequest<AlertRecord> request = new PageRequest<>();
        AlertRecord record = new AlertRecord();
        request.setData(record);
        Paging<AlertRecord> paging = alertService.selectAlertRecordPage(request);
        object.put("alarmTotal",paging.getTotal());
        object.put("maintenanceTotal",221);
        return object;
    }
}
